﻿import java.io.BufferedInputStream;
import java.io.IOException;

/**
 * 负责记录Eterm的传输协议。
 * 同时，也负责某些传输协议的组成。
 * @author hech
 *
 */
public class EtermProtocol {

	/**
	 * 登陆时所需要发送的数据。 再后面是终端信息，一般可不用处理
	 */
	private final byte[] SEND_LOGIN_DATA = new byte[] { 0x01,
			(byte) 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
			 };

	/**
	 * 接受到的成功信息。
	 *///0x00, 0x0A, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x40 
	private final byte[] RECV_LOGIN_DATA = new byte[] { 0x00,0x14,0x01,0x00,0x03,0x00,0x00,0x00,0x30,0x51,0x0C,0x00,0x00,(byte)0x8C,(byte)0x8C,0x29,0x00,0x00,(byte)0xA9,(byte)0xA9 };
	//private final byte[] RECV_LOGIN_DATA = new byte[] {0x00, 0x0A, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x40};
	/**
	 * 发送的握手数据1
	 */
	private byte[] SEND_17 = new byte[] { 0x01, (byte) 0xfe, 0x00,
			0x11, 0x14, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00 };

	private byte[] SEND_34 = new byte[]{
			0x01,(byte)0xfe,0x00,0x11,0x14,0x10,0x00,0x02,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x01,(byte)0xfe,0x00,0x11,0x14,0x10,0x00,0x02,0x29,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00
		};
	
	private byte[] SEND_260 = new byte[]{
			0x01,(byte)0xf7,0x01,0x04,0x33,0x33,0x32,0x32,0x30,0x31,0x30,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00
	};
	
	/**
	 * 发送的握手数据2
	 */
	private byte[] SEND_68 = new byte[] { 0x01, (byte) 0xf9, 0x00,
			0x44, 0x00, 0x01, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

	/**
	 * 信息区域的开始数据
	 */
	private byte[] RECV_DATA_PRE = new byte[] {
	// 0x00,0x00,0x00,0x01,0x00,0x51,0x70,0x02,0x1b,0x0b,0x20,0x20,0x0f,0x1b,0x4d
			// 为了适应多种返回值，进一步削减前缀适配
			0x0f, 0x1b };

	/**
	 * 信息区域的结束数据，第一种可能
	 */
	private byte[] RECV_DATA_POST_0 = new byte[] {
	// 0x0d,0x1e,0x1b,0x62,0x03
	0x0d };

	/**
	 * 第二种可能。
	 */
	private byte[] RECV_DATA_POST_1 = new byte[] {
	// 0x0d,0x1e,0x1b,0x62,0x03
	0x1e };

	
	private byte[] NULL_DATA_0 = new byte[] { 0x01, (byte) 0xfa, 0x00,
			0x05, 0x00 };

	
	private byte[] NULL_DATA_1 = new byte[] { 0x01, 0x00, 0x00, 0x0e,
			0x00, 0x00, 0x00, 0x01, 0x00, 0x51, 0x70, 0x07, 0x02, 0x03 };

	
	private byte[] NULL_DATA_2 = new byte[] { 0x01, 0x00, 0x00, 0x0d,
			0x00, 0x00, 0x00, 0x01, 0x00, 0x51, 0x70, 0x02, 0x03 };

	
	private byte[] SEND_CMD_PRE = new byte[] { 0x01, 0x00, 0x00,
			0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x51, 0x70, 0x02, 0x1b, 0x0b,
			0x20, 0x20, 0x00, 0x0f };
	/**
	 * 发送指令的后缀
	 */
	private byte[] SEND_CMD_POST = new byte[] { 0x20, 0x03 };
	
	/**
	 * 获得登陆数据
	 * 
	 * @return
	 */
	public byte[] getLoginData(String username, String password) {
		byte[] data = new byte[SEND_LOGIN_DATA.length];
		System.arraycopy(SEND_LOGIN_DATA, 0, data, 0,
				data.length);
		byte[] unb = username.getBytes();
		byte[] pwb = password.getBytes();
		int unsize = unb.length;
		if (unsize > 16)
			unsize = 16;
		int pwsize = pwb.length;
		if (pwsize > 16)
			pwsize = 16;
		System.arraycopy(unb, 0, data, 2, unsize);
		System.arraycopy(pwb, 0, data, 18, pwsize);
		return data;
	}

	public byte[] getLoginSend17(){
		return this.SEND_17;
	}
	public byte[] getLoginSend34(){
		return this.SEND_34;
	}
	public byte[] getLoginSend68(){
		return this.SEND_68;
	}
	
	public byte[] getLoginSend260(){
		return this.SEND_260;
	}
	/**
	 * 检查登陆标记
	 * @param data
	 * @return
	 */
	public boolean checkLogin(byte[] data) {
		boolean isok = false;
//		ByteArrayUtils.printByteArray(data);
//		ByteArrayUtils.printByteArray(RECV_LOGIN_DATA);
		if (data.length == RECV_LOGIN_DATA.length) {
			if (data[0] == RECV_LOGIN_DATA[0] && data[1] == RECV_LOGIN_DATA[1]
					&& data[2] == RECV_LOGIN_DATA[2]
					&& data[3] == RECV_LOGIN_DATA[3]
					&& data[4] == RECV_LOGIN_DATA[4]
					&& data[5] == RECV_LOGIN_DATA[5]
					&& data[6] == RECV_LOGIN_DATA[6]
					&& data[7] == RECV_LOGIN_DATA[7]
					) {
				//替换0x00,0x51标识，当前还不知道具体作用。
				byte[] src = new byte[]{0x00,0x51};
				byte[] info = new byte[]{data[8],data[9]};
				SEND_CMD_PRE = ByteArrayUtils.replace(SEND_CMD_PRE,src , info );
				NULL_DATA_1 = ByteArrayUtils.replace(NULL_DATA_1,src , info );
				NULL_DATA_2 = ByteArrayUtils.replace(NULL_DATA_2,src , info );
				isok = true;
			}
		}
		return isok;
	}
	
	/**
	 * 此处设定sequence，从0x20到最大0x37。
	 * 作用不明，暂定设定为都是0x20。
	 */
	private int clientSequence = 0x20;
	
	private int serverSequence = 0x21;
	
	/**
	 * 获得要发送的数据
	 * @param cmd
	 * @return
	 */
	public byte[] getSendData(String cmd){
		byte[] senddata = ByteArrayUtils.combine(SEND_CMD_PRE,USASUtils.convertChineseData(cmd),SEND_CMD_POST);
		byte[] lb = ByteArrayUtils.intToByteArray(senddata.length);
		senddata[1] = lb[1];
		senddata[2] = lb[2];
		senddata[3] = lb[3];
		senddata[14] = (byte)clientSequence;
//		System.out.println(cmd);
//		ByteArrayUtils.printBytes(senddata);
		doSequence();
		
		return senddata;
	}
	
	/**
	 * 做顺序
	 */
	private void doSequence(){
//		System.out.println("doSequence!");
		if (clientSequence==0x36){
			clientSequence = 0x20;
			serverSequence = 0x37;
		}else{
			clientSequence+=2;
			serverSequence = clientSequence-1;
		}
	}
	
	/**
	 * 检查数据情况，是否为空数据，如果是空数据，则需要重新去取
	 * @return
	 */
	private boolean checkEtermData(byte[] source){
		if (ByteArrayUtils.deepEquals(source, NULL_DATA_0)
				||ByteArrayUtils.deepEquals(source, NULL_DATA_1)
				||ByteArrayUtils.deepEquals(source, NULL_DATA_2)
				){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 检查过的解析规则。根据sequence情况
	 * @param in
	 * @return
	 * @throws IOException
	 */
	public EtermData checkedParseEtermData(EtermData edata,BufferedInputStream in) throws IOException{
//		for (int i=0;i<100;i++){
			edata = parseEtermData(edata,in);
//			System.out.println("匹配"+edata.source[14]+":"+serverSequence);
//			if (edata.length>14&&edata.source[14]==serverSequence){
//				break;
//			}else{
//				System.out.println("匹配失败！"+edata.source[14]+":"+serverSequence);
//				System.out.println(edata.getData());
//			}
//		}
		return edata;
	}
	
	/**
	 * 如果第二个字节为0x00，那么三四字节肯定是此次传输数据大小。
	 */
	public EtermData parseEtermData(EtermData edata,BufferedInputStream in) throws IOException{
		//数据的起始位置
		int datastart = 0;
		int length = 0;
		byte[] source = null;
		do{
			int p0 = in.read();
			int p1 = in.read();
			int p2 = in.read();
			int p3 = in.read();
			if (p1>0&&p1<0xf0){
				length = p1;
				datastart = 2;
			}else{
				length = p2*256+p3;
				datastart = 4;
			}
			if(length<0)
				return null;
			source = new byte[length];
			source[0] = (byte)p0;
			source[1] = (byte)p1;
			source[2] = (byte)p2;
			source[3] = (byte)p3;
			in.read(source, 4, source.length-4);
		}while(checkEtermData(source));
		byte[] temp = ByteArrayUtils.subEtermBytes(source);
		//除掉类似*b的字符
		temp = ByteArrayUtils.remove(temp, new byte[]{0x1b,0x62});
		
		edata.data = new String(USASUtils.unconvertChineseData(temp));
		edata.source = source;
		return edata;
	}
	

	public void main(String[] args) {

	}

}
